package org.dreamwork.tools.simulator.connector.web;

import com.google.gson.Gson;
import org.dreamwork.tools.simulator.connector.data.DummyInterface;
import org.dreamwork.tools.simulator.connector.data.DummyVariable;
import org.dreamwork.tools.simulator.connector.data.RequestLog;
import org.dreamwork.tools.simulator.connector.data.WebResult;
import org.dreamwork.tools.simulator.connector.managed.DummyInterfaceService;
import org.dreamwork.injection.IObjectContext;
import org.dreamwork.tools.simulator.connector.managed.DummyVariableService;
import org.dreamwork.tools.simulator.connector.managed.RequestLogService;
import org.dreamwork.util.IOUtil;
import org.dreamwork.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@WebServlet (urlPatterns = "/backend/*")
public class BackendServlet extends HttpServlet {
    private static final String CONTENT_TYPE = "application/json;charset=utf-8";
    private static final Pattern P_DI = Pattern.compile ("^/di/([a-z\\d]*)$");

    private DummyInterfaceService service;
    private DummyVariableService  varService;
    private RequestLogService logService;
    private final Logger logger = LoggerFactory.getLogger (BackendServlet.class);

    @Override
    public void init (ServletConfig config) throws ServletException {
        super.init (config);

        IObjectContext ctx = (IObjectContext) config.getServletContext ().getAttribute (IObjectContext.class.getCanonicalName ());
        service = ctx.getBean (DummyInterfaceService.class);
        varService = ctx.getBean (DummyVariableService.class);
        logService = ctx.getBean (RequestLogService.class);
    }

    @Override
    protected void service (HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType (CONTENT_TYPE);
        String pathInfo = request.getPathInfo ();
        if (StringUtil.isEmpty (pathInfo)) pathInfo = "/";
        WebResult result = null;
        try {
            switch (pathInfo) {
                case "/create":
                    result = create (request);
                    break;
                case "/delete":
                    result = delete (request);
                    break;
                case "/update":
                    result = update (request);
                    break;
                case "/list":
                    result = list (request);
                    break;

                case "/create-var":
                    result = createVariable (request);
                    break;
                case "/list-variables":
                    result = listVariables ();
                    break;

                case "/logs":
                    result = findLogs (request);
                    break;

                default:
                    Matcher m = P_DI.matcher (pathInfo);
                    if (m.matches ()) {
                        String id = m.group (1);
                        result = detail (id);
                    }
                    break;
            }
        } catch (Exception ex) {
            logger.warn (ex.getMessage (), ex);
            result = new WebResult (false, null, ex.getMessage ());
            response.setStatus (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.getWriter ().write (new Gson ().toJson (result));
        }
        if (result == null) {
            response.setStatus (HttpServletResponse.SC_NOT_FOUND);
            response.getWriter ().write ("Resource Not Found.");
        } else {
            Gson g = new Gson ();
            response.getWriter ().write (g.toJson (result));
        }
    }

    private WebResult create (HttpServletRequest request) throws IOException {
        Gson g = new Gson ();
        String content = readBody (request);
        DummyInterface di = g.fromJson (content, DummyInterface.class);
        return service.save (di);
    }

    private WebResult delete (HttpServletRequest request) {
        String id = request.getParameter ("id");
        if (!StringUtil.isEmpty (id)) {
            service.delete (id);
            return new WebResult (true, null, null);
        } else {
            return new WebResult (false, null, "接口未找到");
        }
    }

    private WebResult update (HttpServletRequest request) throws IOException {
        String content = readBody (request);
        Gson g = new Gson ();
        DummyInterface di = g.fromJson (content, DummyInterface.class);
        return service.update (di);
    }

    private WebResult list (HttpServletRequest request) {
        String name = request.getParameter ("name");
        int pageNo = parseOrDefault (request.getParameter ("pageNo"), 1),
            pageSize = parseOrDefault (request.getParameter ("pageSize"), 30);
        List<DummyInterface> list = service.findInterfaces (name, pageNo, pageSize);
        return new WebResult (true, list, null);
    }

    private WebResult createVariable (HttpServletRequest request) throws IOException {
        String content = readBody (request);
        DummyVariable var = new Gson ().fromJson (content, DummyVariable.class);
        try {
            varService.create (var);
            return new WebResult ();
        } catch (Exception ex) {
            return new WebResult (false, null, ex.getMessage ());
        }
    }

    private WebResult findLogs (HttpServletRequest request) {
        String interfaceId = request.getParameter ("if-id");
        if (StringUtil.isEmpty (interfaceId)) {
            return new WebResult (false, null, "parameter [if-id] is missing");
        }
        String s_page_no = request.getParameter ("pn");
        String s_page_size = request.getParameter ("ps");
        int pageNo = 1, pageSize = 30;
        try {
            pageNo = Integer.parseInt (s_page_no);
        } catch (Exception ignore) {}
        try {
            pageSize = Integer.parseInt (s_page_size);
        } catch (Exception ignore) {}
        List<RequestLog> requestLogs = logService.findRequestLogs (interfaceId, pageNo, pageSize);
        return new WebResult (true, requestLogs, null);
    }

    private WebResult detail (String id) {
        return new WebResult (true, service.getDetail (id), null);
    }

    private WebResult listVariables () {
        return new WebResult (true, varService.list (), null);
    }

    private String readBody (HttpServletRequest request) throws IOException {
        byte[] buff = IOUtil.read (request.getInputStream ());
        return new String (buff, StandardCharsets.UTF_8);
    }

    private int parseOrDefault (String e, int d) {
        if (!StringUtil.isEmpty (e)) {
            try {
                return Integer.parseInt (e);
            } catch (Exception ex) {
                if (logger.isTraceEnabled ()) {
                    logger.warn (ex.getMessage (), ex);
                }
            }
        }

        return d;
    }
}